package com.opencee.cloud.uaa.provider;


import com.opencee.cloud.uaa.constants.AuthCode;
import com.opencee.cloud.uaa.constants.UaaConstants;
import com.opencee.cloud.uaa.token.CaptchaAuthenticationToken;
import com.opencee.common.utils.RedisTemplateUtil;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.util.StringUtils;

/**
 * 验证码登陆
 *
 * @author yadu
 */
public class CaptchaAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

    private UserDetailsService userDetailsService;
    private RedisTemplateUtil redisTemplateUtil;
    private PasswordEncoder passwordEncoder;

    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, Authentication authentication) throws AuthenticationException {
        if (authentication.getCredentials() == null) {
            this.logger.debug("Authentication failed: no credentials provided");
            throw new BadCredentialsException(this.messages.getMessage("CaptchaAuthenticationProvider.badCredentials", "Bad credentials"));
        } else {
            CaptchaAuthenticationToken captcha = (CaptchaAuthenticationToken) authentication;
            String key = UaaConstants.CACHE_LOGIN_CAPTCHA_KEY + captcha.getRid();
            String cacheCode = redisTemplateUtil.getString(key);
            if(StringUtils.isEmpty(cacheCode)){
                throw new BadCredentialsException(AuthCode.CAPTCHA_EXPIRED.getMessage());
            }
            // 验证验证码是否匹配
            if (!captcha.getCode().toUpperCase().equals(cacheCode.toUpperCase())) {
                throw new BadCredentialsException(AuthCode.BAD_CAPTCHA.getMessage());
            }
            String presentedPassword = authentication.getCredentials().toString();
            if (!passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
                logger.debug("Authentication failed: password does not match stored value");
                throw new BadCredentialsException(messages.getMessage(
                        "AbstractUserDetailsAuthenticationProvider.badCredentials",
                        "Bad credentials"));
            }
            // 检查成功,删除key
            redisTemplateUtil.del(key);
        }
    }

    @Override
    protected Authentication createSuccessAuthentication(Object principal, Authentication authentication, UserDetails user) {
        CaptchaAuthenticationToken result = new CaptchaAuthenticationToken(principal, authentication.getCredentials(), user.getAuthorities());
        result.setDetails(authentication.getDetails());
        return result;
    }

    @Override
    protected UserDetails retrieveUser(String qrCode, Authentication authentication) throws AuthenticationException {
        UserDetails loadedUser;
        try {
            loadedUser = this.getUserDetailsService().loadUserByUsername(qrCode);
        } catch (UsernameNotFoundException var6) {
            throw var6;
        } catch (Exception var7) {
            throw new InternalAuthenticationServiceException(var7.getMessage(), var7);
        }

        if (loadedUser == null) {
            throw new InternalAuthenticationServiceException("UserDetailsService returned null, which is an interface contract violation");
        } else {
            return loadedUser;
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return CaptchaAuthenticationToken.class.isAssignableFrom(authentication);
    }


    public UserDetailsService getUserDetailsService() {
        return userDetailsService;
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

    public RedisTemplateUtil getRedisTemplateUtil() {
        return redisTemplateUtil;
    }

    public void setRedisTemplateUtil(RedisTemplateUtil redisTemplateUtil) {
        this.redisTemplateUtil = redisTemplateUtil;
    }

    public PasswordEncoder getPasswordEncoder() {
        return passwordEncoder;
    }

    public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }
}
